package rainy.file.synchronization.client;

import java.io.File;
import java.io.FileInputStream;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;

import com.alibaba.fastjson.JSON;

import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import rainy.file.synchronization.client.channel.ChannelFactory;
import rainy.file.synchronization.client.file.FolderMonitor;
import rainy.file.synchronization.client.file.traverse.FileStructure;
import rainy.file.synchronization.client.file.traverse.LocalFileTraverser;
import rainy.file.synchronization.config.RainyRunTime;
import rainy.file.synchronization.log.MDC;

/**
 * 
 * @author Grom
 *
 */
public class FileSendClient {

	private String host = RainyRunTime.getStringPropDefine("rainy.master.serverName", "localhost");
	private int port = RainyRunTime.getIntegerPropDefine("rainy.master.port", 9054);
	public static String monitorFolder = RainyRunTime.monitorFolder;
	private static BlockingQueue<File> modifiedFilesQueue = new LinkedBlockingDeque<>();
	private static final Object key = new Object();
	private static final String clientType = "fileSender";
	private static final String healthCheck = RainyRunTime.getStringPropDefine("rainy.health.check", "localhost");

	public FileSendClient() {

	}

	static {
		MDC.gPush("type", "FILE");
	}

	public FileSendClient(String host, int port) {
		this.host = host;
		this.port = port;
	}

	public static void addNewAddedFile(File file) {
		synchronized (key) {
			modifiedFilesQueue.add(file);
		}
	}

	public void run() throws Exception {
		EventLoopGroup group = new NioEventLoopGroup();
		try {
			// init channel while start!
			Channel channel = ChannelFactory.getCurrentChannel(clientType, group);
			System.out.println("[ client ] Client is started to connect [" + host + ":" + port + "]");
			new FolderMonitor(monitorFolder).start();
			System.out.println("[ client ] Monitor is started!");

			if (healthCheck.equals("true")) {
				sendHealthCheck(group);
			}
			boolean exit = false;
			while (true && !exit) {
				File newFile = null;
				newFile = modifiedFilesQueue.take();
				System.out.println("Start to sync file : " + newFile);
				if (newFile == null) {
					Thread.sleep(1000);
					continue;
				}
				String sendStr = newFile.getPath().substring(monitorFolder.length()) + "#";
				// 发送该文件
				while (true) {
					Thread.sleep(100);
					if (newFile.getParentFile().exists() && newFile.exists() && newFile.canWrite()) {
						FileInputStream fins = new FileInputStream(newFile);
						byte[] buffer = new byte[fins.available()];
						fins.read(buffer);
						fins.close();
						byte[] b = new org.apache.commons.codec.binary.Base64().encode(buffer);
						sendStr += new String(b);
						channel = ChannelFactory.getCurrentChannel(clientType, group);
						channel.writeAndFlush(sendStr + "\r\n");
						break;
					}
				}
			}
		} finally {
			group.shutdownGracefully();
		}
	}

	/**
	 * 系统启动的时候可以选择进行一次health check，以确认服务端跟客户端具有相同的文件结构
	 */
	public void sendHealthCheck(EventLoopGroup group) {
		FileStructure structure = LocalFileTraverser.generateFileStructure(new File(RainyRunTime.monitorFolder), null);
		String healthCommand = RainyRunTime.COMMOND_HEALTH_CHECK + RainyRunTime.COMMAND_CONTENT_SPLIT;
		healthCommand += JSON.toJSONString(structure);
		Channel channel = ChannelFactory.getCurrentChannel(clientType, group);
		channel.writeAndFlush(healthCommand + "\r\n");
	}

	public static void main(String[] args) throws Exception {
		new FileSendClient().run();
	}
}